#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ctype.h>
#include <time.h>
#include <limits.h>

#define LEN 81
#define SWAP(type, a, b)    do {type c=a; a=b; b=c;} while(0)

#define SOLID   0
#define DOTTED  1
#define DASHED  2

#define RED     1
#define GREEN   2
#define BLUE    4

#define BLACK   0
#define YELLOW  (RED | GREEN)
#define MAGENTA (RED | BLUE)
#define CYAN    (GREEN | BLUE)
#define WHITE   (RED | GREEN | BLUE)


#define OPAQUE      0x1
#define FILL_BLUE   0x8
#define FILL_GREEN  0x4
#define FILL_RED    0x2
#define FILL_MASK   0xE

#define BORDER      0x100
#define BORDER_BLUE 0x800
#define BORDER_GREEN    0x400
#define BORDER_RED  0x200
#define BORDER_MASK 0xE00

#define B_SOLID     0
#define B_DOTTED    0x1000
#define B_DASHED    0x2000
#define STYLE_MASK  0x3000

const char * colors[8] = {
    "black",
    "red",
    "green",
    "yellow",
    "blue",
    "magenta",
    "cyan",
    "white",
};

struct box_props {
    bool opaque : 1;
    unsigned int fill_color : 3;
    unsigned int : 4;
    bool show_border : 1;
    unsigned int border_color : 3;
    unsigned int border_style : 2;
    unsigned int : 2;
};


static const int I_BIT_SIZE = CHAR_BIT * sizeof(int);

union Views {
    struct box_props st_view;
    unsigned short us_view;
};

void show_settings(const struct box_props * pb);
void show_settings1(unsigned short);

char * itobs(int n, char * ps);
void print_bin(char *);

int main(void)
{

    union Views box = {{true, YELLOW, true, GREEN, DASHED}};
    char bin_str[ I_BIT_SIZE+ 1];

    printf("Original box settings:\n");
    show_settings(&box.st_view);
    printf("\nBox settings using unsigned int view.\n");
    show_settings1(box.us_view);

    printf("bits are ");
    itobs(box.us_view, bin_str);
    print_bin(bin_str);
    putchar('\n');

    box.us_view &= ~FILL_MASK;
    box.us_view |= (FILL_BLUE | FILL_GREEN);

    box.us_view ^= OPAQUE;
    box.us_view |= BORDER_RED;
    box.us_view &= ~STYLE_MASK;
    box.us_view |= B_DOTTED;

    printf("\nModified box settings:\n");
    show_settings(&box.st_view);

    printf("\nBox settings using unsigned int view:\n");
    show_settings1(box.us_view);

    printf("bits are ");
    itobs(box.us_view, bin_str);
    print_bin(bin_str);
    putchar('\n');

    return 0;
}

void show_settings(const struct box_props * pb)
{
    printf("Box is %s.\n", pb->opaque == true? "opaque": "transparent");
    printf("The fill color is %s.\n", colors[pb->fill_color]);
    printf("Border %s.\n", pb->show_border == true? "shown": "not shown");
    printf("The border color is %s.\n", colors[pb->border_color]);
    printf("The border style is ");
    switch (pb->border_style) {
        case SOLID:
            printf("solid.\n"); break;
        case DOTTED:
            printf("dotted.\n"); break;
        case DASHED:
            printf("dashed.\n"); break;
        default:
            printf("unknow type.\n");
    }
}

void show_settings1(unsigned short us)
{
    printf("Box is %s.\n", us & OPAQUE? "opaque": "transparent");
    printf("The fill color is %s.\n", colors[(us & FILL_MASK) >> 1]);
    printf("Border %s.\n", us & BORDER? "shown": "not shown");
    printf("The border color is %s.\n", colors[(us &  BORDER_MASK) >> 9]);
    printf("The border style is ");

    switch (us & STYLE_MASK) {
        case B_SOLID:
            printf("solid.\n"); break;
        case B_DOTTED:
            printf("dotted.\n"); break;
        case B_DASHED:
            printf("dashed.\n"); break;
    }
}

char * itobs(int n, char * ps)
{
    int i;
    int size = I_BIT_SIZE;

    for (i=size-1; i>=0; --i, n>>=1)
        ps[i] = '0' + (01 & n);

    ps[size] = 0;

    return ps;
}

void print_bin(char * s)
{
    int i;
    while (*s)
    {
        putchar(*s++);
        if (++i % 4 == 0)
            putchar(' ');
    }
}

char * s_gets(char * str, int n)
{
    char * ret_val;
    char * find;

    if ((ret_val = fgets(str, n, stdin))) {
        find = strchr(str, '\n');
        if (find)
            *find = 0;
        else
            while (getchar() != '\n')
                ;
    }

    return ret_val;
}
